package com.warrantyhotel.android.billing;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.text.Html;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;

import com.warrantyhotel.android.R;
import com.warrantyhotel.android.adapter.BuyCreditsAdapter;
import com.warrantyhotel.android.billing.BillingService.RequestPurchase;
import com.warrantyhotel.android.billing.BillingService.RestoreTransactions;
import com.warrantyhotel.android.billing.Consts.PurchaseState;
import com.warrantyhotel.android.billing.Consts.ResponseCode;
import com.warrantyhotel.android.db.QueriesCodes;
import com.warrantyhotel.android.model.Keys;
import com.warrantyhotel.android.model.PurchaseObject;
import com.warrantyhotel.android.service.UpdateIntentService;
import com.warrantyhotel.android.util.DetachableResultReceiver;
import com.warrantyhotel.android.util.DetachableResultReceiver.Receiver;

public class BuyCredits extends Activity implements OnItemClickListener, Receiver {

	// private String mItemName;
	// private String mSku;

	private static final String TAG = BuyCredits.class.getSimpleName();

	/**
	 * Used for storing the log text.
	 */
	private static final String LOG_TEXT_KEY = "DUNGEONS_LOG_TEXT";

	/**
	 * The SharedPreferences key for recording whether we initialized the
	 * database. If false, then we perform a RestoreTransactions request to get
	 * all the purchases for this user.
	 */
	private static final String DB_INITIALIZED = "db_initialized";

	private DungeonsPurchaseObserver mDungeonsPurchaseObserver;
	private Handler mHandler;

	private BillingService mBillingService;
	// private Button mBuyButton;
	// private Button mEditPayloadButton;
	private TextView mLogTextView;
	// private Spinner mSelectItemSpinner;
	private ListView mOwnedItemsTable;
	// private SimpleCursorAdapter mOwnedItemsAdapter;
	private PurchaseDatabase mPurchaseDatabase;
	private Cursor mOwnedItemsCursor;
	private SimpleCursorAdapter mOwnedItemsAdapter;
	private ProgressDialog progress;
	private DetachableResultReceiver receiver;
	private ListView list;
	private ArrayList<PurchaseObject> listItems;
	// private Set<String> mOwnedItems = new HashSet<String>();

	/**
	 * The developer payload that is sent with subsequent purchase requests.
	 */
	// private String mPayloadContents = null;

	private static final int DIALOG_CANNOT_CONNECT_ID = 1;
	private static final int DIALOG_BILLING_NOT_SUPPORTED_ID = 2;

	/**
	 * Each product in the catalog is either MANAGED or UNMANAGED. MANAGED means
	 * that the product can be purchased only once per user (such as a new level
	 * in a game). The purchase is remembered by Android Market and can be
	 * restored if this application is uninstalled and then re-installed.
	 * UNMANAGED is used for products that can be used up and purchased multiple
	 * times (such as poker chips). It is up to the application to keep track of
	 * UNMANAGED products for the user.
	 */
	// private enum Managed { MANAGED, UNMANAGED }

	/**
	 * A {@link PurchaseObserver} is used to get callbacks when Android Market
	 * sends messages to this application so that we can update the UI.
	 */
	private class DungeonsPurchaseObserver extends PurchaseObserver {
		public DungeonsPurchaseObserver(Handler handler) {
			super(BuyCredits.this, handler);
		}

		@Override
		public void onBillingSupported(boolean supported) {
			if (Consts.DEBUG) {
				Log.i(TAG, "supported: " + supported);
			}
			if (supported) {
				restoreDatabase();
				// mBuyButton.setEnabled(true);
				// mEditPayloadButton.setEnabled(true);
			} else {
				showDialog(DIALOG_BILLING_NOT_SUPPORTED_ID);
			}
		}

		@Override
		public void onPurchaseStateChange(PurchaseState purchaseState, String itemId, int quantity, long purchaseTime, String developerPayload) {
			if (Consts.DEBUG) {
				Log.i(TAG, "onPurchaseStateChange() itemId: " + itemId + " " + purchaseState);
			}

			// ToastUtil.showText(getApplicationContext(), itemId + " " +
			// purchaseState);
			if (developerPayload == null) {
				logProductActivity(itemId, purchaseState.toString());
			} else {
				logProductActivity(itemId, purchaseState + "\n\t" + developerPayload);
			}

			if (purchaseState == PurchaseState.PURCHASED) {
				// mOwnedItems.add(itemId);
			}
			// mCatalogAdapter.setOwnedItems(mOwnedItems);
			mOwnedItemsCursor.requery();
		}

		@Override
		public void onRequestPurchaseResponse(RequestPurchase request, ResponseCode responseCode) {
			if (Consts.DEBUG) {
				Log.d(TAG, request.mProductId + ": " + responseCode);
			}

			// ToastUtil.showText(getApplicationContext(), " " + responseCode);

			if (responseCode == ResponseCode.RESULT_OK) {
				if (Consts.DEBUG) {
					Log.i(TAG, "purchase was successfully sent to server");
				}

				// Intent loginIntent = new Intent(Intent.ACTION_SYNC, null,
				// BuyCredits.this, UpdateIntentService.class);
				// loginIntent.putExtra(UpdateIntentService.EXTRA_REQUEST_CODE,
				// QueriesCodes.SUBMIT_PURCHASE);
				// startService(loginIntent);

				logProductActivity(request.mProductId, "sending purchase request");
			} else if (responseCode == ResponseCode.RESULT_USER_CANCELED) {
				if (Consts.DEBUG) {
					Log.i(TAG, "user canceled purchase");
				}
				logProductActivity(request.mProductId, "dismissed purchase dialog");
			} else {
				if (Consts.DEBUG) {
					Log.i(TAG, "purchase failed");
				}
				logProductActivity(request.mProductId, "request purchase returned " + responseCode);
			}
		}

		@Override
		public void onRestoreTransactionsResponse(RestoreTransactions request, ResponseCode responseCode) {
			if (responseCode == ResponseCode.RESULT_OK) {
				if (Consts.DEBUG) {
					Log.d(TAG, "completed RestoreTransactions request");
				}
				// Update the shared preferences so that we don't perform
				// a RestoreTransactions again.
				SharedPreferences prefs = getPreferences(Context.MODE_PRIVATE);
				SharedPreferences.Editor edit = prefs.edit();
				edit.putBoolean(DB_INITIALIZED, true);
				edit.commit();
			} else {
				if (Consts.DEBUG) {
					Log.d(TAG, "RestoreTransactions error: " + responseCode);
				}
			}
		}
	}

	private void getPurchaseItems() {
		Intent purchaseIntent = new Intent(Intent.ACTION_SYNC, null, this, UpdateIntentService.class);
		purchaseIntent.putExtra(UpdateIntentService.EXTRA_STATUS_RECEIVER, receiver);
		purchaseIntent.putExtra(UpdateIntentService.EXTRA_REQUEST_CODE, QueriesCodes.PURCHASE);
		startService(purchaseIntent);
	}

	@Override
	protected void onCreate(Bundle savedInstanceState) {

		// TODO

		super.onCreate(savedInstanceState);
		setContentView(R.layout.buy_credits);
		mLogTextView = (TextView) findViewById(R.id.log);

		receiver = new DetachableResultReceiver(new Handler());
		receiver.setReceiver(this);
		progress = ProgressDialog.show(this, getString(R.string.loading), getString(R.string.please_wait), true, false);
		getPurchaseItems();

		list = (ListView) findViewById(R.id.buy_credit_list);
		list.setOnItemClickListener(this);

		mHandler = new Handler();
		mDungeonsPurchaseObserver = new DungeonsPurchaseObserver(mHandler);
		mBillingService = new BillingService();
		mBillingService.setContext(this);

		mPurchaseDatabase = new PurchaseDatabase(this);
		mOwnedItemsCursor = mPurchaseDatabase.queryAllPurchasedItems();
		startManagingCursor(mOwnedItemsCursor);
		String[] from = new String[] { PurchaseDatabase.PURCHASED_PRODUCT_ID_COL, PurchaseDatabase.PURCHASED_QUANTITY_COL };
		int[] to = new int[] { R.id.item_name, R.id.item_quantity };
		mOwnedItemsAdapter = new SimpleCursorAdapter(this, R.layout.item_row, mOwnedItemsCursor, from, to);
		mOwnedItemsTable = (ListView) findViewById(R.id.owned_items);
		mOwnedItemsTable.setAdapter(mOwnedItemsAdapter);

		// Log.v(TAG, "" + mOwnedItemsCursor.getCount());

		// setupWidgets();

		// Check if billing is supported.
		ResponseHandler.register(mDungeonsPurchaseObserver);
		if (!mBillingService.checkBillingSupported()) {
			showDialog(DIALOG_CANNOT_CONNECT_ID);
		}

	}

	@Override
	public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
		if (!mBillingService.requestPurchase(listItems.get(position).getInAppProductID(), null)) {
			showDialog(DIALOG_BILLING_NOT_SUPPORTED_ID);
		}

		// switch (position) {
		// case 0:
		//
		// // if (!mBillingService.requestPurchase("android.test.purchased",
		// // null)) {
		// // showDialog(DIALOG_BILLING_NOT_SUPPORTED_ID);
		// // }
		//
		// // if (!mBillingService.requestPurchase("android.test.canceled",
		// // null)) {
		// // showDialog(DIALOG_BILLING_NOT_SUPPORTED_ID);
		// // }
		//
		// if (!mBillingService.requestPurchase("010c005u_v1.0_android", null))
		// {
		// showDialog(DIALOG_BILLING_NOT_SUPPORTED_ID);
		// }
		//
		// break;
		// case 1:
		// if (!mBillingService.requestPurchase("020c015u_v1.0_android", null))
		// {
		// showDialog(DIALOG_BILLING_NOT_SUPPORTED_ID);
		// }
		// // if (!mBillingService.requestPurchase("free_item", null)) {
		// // showDialog(DIALOG_BILLING_NOT_SUPPORTED_ID);
		// // }
		//
		// break;
		// case 2:
		// if (!mBillingService.requestPurchase("050c050u_v1.2_android", null))
		// {
		// showDialog(DIALOG_BILLING_NOT_SUPPORTED_ID);
		// }
		// break;
		// case 3:
		// if (!mBillingService.requestPurchase("001c050u_v1.0_android", null))
		// {
		// showDialog(DIALOG_BILLING_NOT_SUPPORTED_ID);
		// }
		// break;
		//
		// // if (!mBillingService
		// // .requestPurchase("android.test.purchased", null)) {
		// // showDialog(DIALOG_BILLING_NOT_SUPPORTED_ID);
		// // }
		// default:
		// break;
		// }

	}

	/**
	 * Called when this activity becomes visible.
	 */
	@Override
	protected void onStart() {
		super.onStart();
		ResponseHandler.register(mDungeonsPurchaseObserver);
		initializeOwnedItems();
	}

	/**
	 * Called when this activity is no longer visible.
	 */
	@Override
	protected void onStop() {
		super.onStop();
		ResponseHandler.unregister(mDungeonsPurchaseObserver);
	}

	@Override
	protected void onDestroy() {
		super.onDestroy();
		mPurchaseDatabase.close();
		mBillingService.unbind();
	}

	/**
	 * Save the context of the log so simple things like rotation will not
	 * result in the log being cleared.
	 */
	@Override
	protected void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);
		outState.putString(LOG_TEXT_KEY, Html.toHtml((Spanned) mLogTextView.getText()));
	}

	/**
	 * Restore the contents of the log if it has previously been saved.
	 */
	@Override
	protected void onRestoreInstanceState(Bundle savedInstanceState) {
		super.onRestoreInstanceState(savedInstanceState);
		if (savedInstanceState != null) {
			mLogTextView.setText(Html.fromHtml(savedInstanceState.getString(LOG_TEXT_KEY)));
		}
	}

	@Override
	protected Dialog onCreateDialog(int id) {
		switch (id) {
		case DIALOG_CANNOT_CONNECT_ID:
			return createDialog(R.string.cannot_connect_title, R.string.cannot_connect_message);
		case DIALOG_BILLING_NOT_SUPPORTED_ID:
			return createDialog(R.string.billing_not_supported_title, R.string.billing_not_supported_message);
		default:
			return null;
		}
	}

	private Dialog createDialog(int titleId, int messageId) {
		String helpUrl = replaceLanguageAndRegion(getString(R.string.help_url));
		if (Consts.DEBUG) {
			Log.i(TAG, helpUrl);
		}
		final Uri helpUri = Uri.parse(helpUrl);

		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setTitle(titleId).setIcon(android.R.drawable.stat_sys_warning).setMessage(messageId).setCancelable(false)
				.setPositiveButton(android.R.string.ok, null).setNegativeButton(R.string.learn_more, new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface dialog, int which) {
						Intent intent = new Intent(Intent.ACTION_VIEW, helpUri);
						startActivity(intent);
					}
				});
		return builder.create();
	}

	/**
	 * Replaces the language and/or country of the device into the given string.
	 * The pattern "%lang%" will be replaced by the device's language code and
	 * the pattern "%region%" will be replaced with the device's country code.
	 * 
	 * @param str
	 *            the string to replace the language/country within
	 * @return a string containing the local language and region codes
	 */
	private String replaceLanguageAndRegion(String str) {
		// Substitute language and or region if present in string
		if (str.contains("%lang%") || str.contains("%region%")) {
			Locale locale = Locale.getDefault();
			str = str.replace("%lang%", locale.getLanguage().toLowerCase());
			str = str.replace("%region%", locale.getCountry().toLowerCase());
		}
		return str;
	}

	private void prependLogEntry(CharSequence cs) {
		SpannableStringBuilder contents = new SpannableStringBuilder(cs);
		contents.append('\n');
		contents.append(mLogTextView.getText());
		mLogTextView.setText(contents);
	}

	private void logProductActivity(String product, String activity) {
		SpannableStringBuilder contents = new SpannableStringBuilder();
		contents.append(Html.fromHtml("<b>" + product + "</b>: "));
		contents.append(activity);
		prependLogEntry(contents);
	}

	/**
	 * If the database has not been initialized, we send a RESTORE_TRANSACTIONS
	 * request to Android Market to get the list of purchased items for this
	 * user. This happens if the application has just been installed or the user
	 * wiped data. We do not want to do this on every startup, rather, we want
	 * to do only when the database needs to be initialized.
	 */
	private void restoreDatabase() {
		SharedPreferences prefs = getPreferences(MODE_PRIVATE);
		boolean initialized = prefs.getBoolean(DB_INITIALIZED, false);
		if (!initialized) {
			mBillingService.restoreTransactions();
			// Toast.makeText(this, R.string.restoring_transactions,
			// Toast.LENGTH_LONG).show();
		}
	}

	/**
	 * Creates a background thread that reads the database and initializes the
	 * set of owned items.
	 */
	private void initializeOwnedItems() {
		new Thread(new Runnable() {
			public void run() {
				doInitializeOwnedItems();
			}
		}).start();
	}

	/**
	 * Reads the set of purchased items from the database in a background thread
	 * and then adds those items to the set of owned items in the main UI
	 * thread.
	 */
	private void doInitializeOwnedItems() {
		Cursor cursor = mPurchaseDatabase.queryAllPurchasedItems();
		if (cursor == null) {
			return;
		}

		final Set<String> ownedItems = new HashSet<String>();
		try {
			int productIdCol = cursor.getColumnIndexOrThrow(PurchaseDatabase.PURCHASED_PRODUCT_ID_COL);
			while (cursor.moveToNext()) {
				String productId = cursor.getString(productIdCol);
				ownedItems.add(productId);
			}
		} finally {
			cursor.close();
		}

		// We will add the set of owned items in a new Runnable that runs on
		// the UI thread so that we don't need to synchronize access to
		// mOwnedItems.
		mHandler.post(new Runnable() {
			public void run() {
				// mOwnedItems.addAll(ownedItems);
				// mCatalogAdapter.setOwnedItems(mOwnedItems);
			}
		});
	}

	@Override
	public void onReceiveResult(int resultCode, Bundle resultData) {
		switch (resultCode) {
		case UpdateIntentService.STATUS_RUNNING:
			break;
		case UpdateIntentService.STATUS_ERROR:
			if (progress != null)
				progress.dismiss();
			finish();
			break;
		case UpdateIntentService.STATUS_FINISHED:
			if (progress != null)
				progress.dismiss();

			listItems = resultData.getParcelableArrayList(Keys._purchase);
			ListAdapter adapter = new BuyCreditsAdapter(getApplicationContext(), R.layout.get_credit_item, listItems);
			list.setAdapter(adapter);

			break;
		}
	}

	/**
	 * Displays the dialog used to edit the payload dialog.
	 */
	// private void showPayloadEditDialog() {
	// AlertDialog.Builder dialog = new AlertDialog.Builder(this);
	// final View view = View.inflate(this, R.layout.edit_payload, null);
	// final TextView payloadText = (TextView)
	// view.findViewById(R.id.payload_text);
	// if (mPayloadContents != null) {
	// payloadText.setText(mPayloadContents);
	// }
	//
	// dialog.setView(view);
	// dialog.setPositiveButton(
	// R.string.edit_payload_accept,
	// new DialogInterface.OnClickListener() {
	// public void onClick(DialogInterface dialog, int which) {
	// mPayloadContents = payloadText.getText().toString();
	// }
	// });
	// dialog.setNegativeButton(
	// R.string.edit_payload_clear,
	// new DialogInterface.OnClickListener() {
	// public void onClick(DialogInterface dialog, int which) {
	// if (dialog != null) {
	// mPayloadContents = null;
	// dialog.cancel();
	// }
	// }
	// });
	// dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
	// public void onCancel(DialogInterface dialog) {
	// if (dialog != null) {
	// dialog.cancel();
	// }
	// }
	// });
	// dialog.show();
	// }

}
